//
//  InstallationScanBarcodeDynamsoftView.swift
//  GreenDeal
//
//  Created by Moennig Q on 15/11/2022.
//

import UIKit
import DynamsoftBarcodeReader
import DynamsoftCameraEnhancer
import HandyJSON
import SwiftyJSON
class DynamsoftScannerView: UIView,ScannerViewProtocal,DBRTextResultListener {
    var decodeCurrentTime = Date()
    let scannerQueue = DispatchQueue(label: "dynamsoft.scanner.queue")
    var isScanning: Bool = false
    var scanAddMethodMode: ScanAddMethodMode = .auto
    var scanResultClosure: ((ScanningResult) -> Void)?
    var takePhotoResultClosure: ((Data)->Void)?
    var enableInvertedBarcodeFlag: Bool = false
    var scanMode: ScanMode = .oneD
    //stroke color
    var strokeColor: UIColor = APPConfig.ScanPanelColor
    //scanner
    private var haveAvailableDeviceFlag: Bool = true
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpView()
    }
    convenience init() {
        self.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setUpView() {
        self.backgroundColor = .black//此处不能改成透明.clear,因为相机关闭会看到后边的list UI
        
    }
    // MARK: - ScannerProtocal
    func launchScanner(enableInvetedFlag: Bool,enableFuzzyFlag: Bool) {
        //获取是否有后置摄像头有效的设备
        self.haveAvailableDeviceFlag = self.checkIfHaveAvailableDevice()
        if self.haveAvailableDeviceFlag {
            //开启绿色定位线框
            ScannerManager.shared.dceView?.overlayVisible = true
            ScannerManager.shared.dce.open()
            self.addSubview(ScannerManager.shared.dceView)
            ScannerManager.shared.barcodeReader?.setDBRTextResultListener(self)
            ScannerManager.shared.barcodeReader?.startScanning()
            self.initDBRSetting(enableInvetedFlag: enableInvetedFlag,enableFuzzyFlag: enableFuzzyFlag)
            self.isScanning = true
        }
    }
    //默认以为码，不识别反色条码，不设置模糊识别
    func initDBRSetting(enableInvetedFlag: Bool,enableFuzzyFlag: Bool){
        if let settings = try? ScannerManager.shared.barcodeReader?.getRuntimeSettings(){
            //第一：设置一维码
            //ios的摄像头拍摄的图片需要逆时针转90度才是屏幕上看到的图片的样子,所以region中的参数left，right代表实际的top，bottom，
            //region中的参数top，bottom代表实际的left，right
            settings.region.regionTop = 0
            settings.region.regionLeft = Int(APPConfig.scanViewTopMargin / UIScreen.main.bounds.height * 100)
            settings.region.regionRight = Int((APPConfig.scanViewTopMargin + APPConfig.scanViewHeight) / UIScreen.main.bounds.height * 100)
            settings.region.regionBottom = 100
            //6.测试只设置条形码是否发烫严重
            settings.barcodeFormatIds = EnumBarcodeFormat.ONED.rawValue
            //1 代表百分比，0是具体的坐标值可
            settings.region.regionMeasuredByPercentage = 1
            //第二：设置反色条码
            if enableInvetedFlag {
                settings.furtherModes.grayscaleTransformationModes = [EnumGrayscaleTransformationMode.original.rawValue, EnumGrayscaleTransformationMode.inverted.rawValue, 0, 0, 0, 0, 0, 0]//2代表original (浅色背景深色码),
            }else{
                settings.furtherModes.grayscaleTransformationModes = [EnumGrayscaleTransformationMode.original.rawValue, 0, 0, 0, 0, 0, 0, 0]//2代表original (浅色背景深色码),
            }
            //第三：设置默认模糊设置：对于模糊的图像，可以将属性设置为较大的值。设置的值越高，库将花费更多的精力来解码图像。然而，这可能会减缓识别过程。
            settings.deblurLevel = 9
            //Fuzzy setting
            if enableFuzzyFlag {
                settings.minResultConfidence = APPConfig.ScannerDeblurConfidence
                ScannerManager.shared.dce?.setZoom(1.6)//开启fuzzy模式时，表示不好识别，加大zoom方便识别
            }else{
                settings.minResultConfidence = APPConfig.ScannerConfidence
                ScannerManager.shared.dce?.setZoom(1)//开启fuzzy模式时，表示不好识别，加大zoom方便识别
            }
            //barcodeReader更新setting放在主线程，在iOS 11,ios 15.7上有卡顿，所以放在子线程中
            scannerQueue.async {
                try? ScannerManager.shared.barcodeReader.updateRuntimeSettings(settings)
            }
            self.printScannerSetting()
        }
    }
    // MARK: - 开始扫描
    func startScanning() {
        if self.isScanning == false && self.haveAvailableDeviceFlag{
            ScannerManager.shared.barcodeReader?.startScanning()
            ScannerManager.shared.dceView?.overlayVisible = true
            self.isScanning = true
            DebugLog("开启扫描")
        }
    }
    // MARK: - 停止扫描
    func stopScanning() {
        if self.isScanning  && self.haveAvailableDeviceFlag{
            ScannerManager.shared.barcodeReader?.stopScanning()
            ScannerManager.shared.dceView.overlayVisible = false
            self.isScanning = false
            DebugLog("关闭扫描")
        }
    }
    // MARK: - 切换是否扫描反色条码
    func switchInverterSetting(_ enabledFlag: Bool){
        if let settings = try? ScannerManager.shared.barcodeReader?.getRuntimeSettings(){
            //如果用户开启了可以扫描反色条形码，扫描库才能扫，否则只能扫白底黑条的条形码
            if enabledFlag {//当前Job开启了反色条码
                settings.furtherModes.grayscaleTransformationModes = [EnumGrayscaleTransformationMode.original.rawValue, EnumGrayscaleTransformationMode.inverted.rawValue, 0, 0, 0, 0, 0, 0]//2代表original (浅色背景深色码), 1代表inverted(深色背景浅色码),即兼容两种颜色的码
            }else{//当前Job没有开启
                settings.furtherModes.grayscaleTransformationModes = [EnumGrayscaleTransformationMode.original.rawValue, 0, 0, 0, 0, 0, 0, 0]
            }
            //
            scannerQueue.async {
                try? ScannerManager.shared.barcodeReader.updateRuntimeSettings(settings)
            }
            self.printScannerSetting()
        }
    }
    //MARK: - 开启扫码模式：一维码或二维码
    func switchScanMode(_ scanMode: ScanMode) {
        self.scanMode = scanMode
        if let settings = try? ScannerManager.shared.barcodeReader?.getRuntimeSettings(){
            if scanMode == .oneD {
                //ios的摄像头拍摄的图片需要逆时针转90度才是屏幕上看到的图片的样子,所以region中的参数left，right代表实际的top，bottom，
                //region中的参数top，bottom代表实际的left，right
                settings.region.regionTop = 0
                settings.region.regionLeft = Int(APPConfig.scanViewTopMargin / UIScreen.main.bounds.height * 100)
                settings.region.regionRight = Int((APPConfig.scanViewTopMargin + APPConfig.scanViewHeight) / UIScreen.main.bounds.height * 100)
                settings.region.regionBottom = 100
                //6.测试只设置条形码是否发烫严重
                settings.barcodeFormatIds = EnumBarcodeFormat.ONED.rawValue
            }else if scanMode == .qrCODE{//二维码
                //ios的摄像头拍摄的图片需要逆时针转90度才是屏幕上看到的图片的样子,所以region中的参数left，right代表实际的top，bottom，
                //region中的参数top，bottom代表实际的left，right
                settings.region.regionTop = Int((APPConfig.WidthForPortrait - APPConfig.qrScanViewWidth) / 2 / APPConfig.WidthForPortrait * 100)
                settings.region.regionLeft = Int(APPConfig.scanViewTopMargin / UIScreen.main.bounds.height * 100)
                settings.region.regionRight = Int((APPConfig.scanViewTopMargin + APPConfig.qrScanViewWidth) / UIScreen.main.bounds.height * 100)
                settings.region.regionBottom = Int(((APPConfig.WidthForPortrait - APPConfig.qrScanViewWidth) / 2 + APPConfig.qrScanViewWidth) / APPConfig.WidthForPortrait * 100)
                //6.测试只设置条形码是否发烫严重
                settings.barcodeFormatIds = EnumBarcodeFormat.QRCODE.rawValue | EnumBarcodeFormat.DATAMATRIX.rawValue
            }
            //1 代表百分比，0是具体的坐标值可
            settings.region.regionMeasuredByPercentage = 1
            //barcodeReader更新setting放在主线程，在iOS 11,ios 15.7上有卡顿，所以放在子线程中
            scannerQueue.async {
//                DebugLog("1.开始改变扫码类型\(Tool().getCurrentDatetime())")
                try? ScannerManager.shared.barcodeReader.updateRuntimeSettings(settings)
//                DebugLog("2.结束改变扫码类型\(Tool().getCurrentDatetime())")
            }
            self.printScannerSetting()
        }
    }
    // MARK: - 是否开启模糊扫码
    func switchFuzzyScanSetting(_ enabledFlag: Bool) {
            if let settings = try? ScannerManager.shared.barcodeReader?.getRuntimeSettings(){
                //如果用户开启了可以扫描模糊形码
                if enabledFlag {//
                    //设置code 的模糊度为最高，处理印刷条码不清晰无法识别的问题
                    settings.deblurLevel = APPConfig.ScannerDeblurLevel
                    settings.minResultConfidence = APPConfig.ScannerDeblurConfidence
                    ScannerManager.shared.dce?.setZoom(1.6)//开启fuzzy模式时，表示不好识别，加大zoom方便识别
                }else{//当前Job没有开启
                    settings.deblurLevel = 9
                    settings.minResultConfidence = APPConfig.ScannerConfidence
                    ScannerManager.shared.dce?.setZoom(1)
                }
                
                scannerQueue.async {
                    try? ScannerManager.shared.barcodeReader.updateRuntimeSettings(settings)
                }
                self.printScannerSetting()
            }
    }
    // MARK: - 拍照
    func takePhoto() {
        ScannerManager.shared.dce?.takePhoto(self)
    }
    func releaseScanner() {
        ScannerManager.shared.pauseScanner()
    }
    // MARK: - DBRTextResultListener
    func textResultCallback(_ frameId: Int, imageData: iImageData, results: [iTextResult]?) {
        if let firstResult = results?.first{
            guard let image = try? imageData.toUIImage() else {
                return
            }
            guard let resultPoints = firstResult.localizationResult?.resultPoints as? [CGPoint] else{
                return
            }
            //auto增加的才处理图片
            
            var resultImageData: Data? = nil
            var scanTime: Int32 = 0
            if self.scanAddMethodMode == .auto{
                if let imageWithLine = self.drawLineOnImage(fromImage: image, corners: resultPoints){
                    resultImageData = imageWithLine.jpegData(compressionQuality: 1.0)
                }
                //识别时间,
                let now = Date()
                scanTime = Int32(lround(now.timeIntervalSince1970 * 1000 - self.decodeCurrentTime.timeIntervalSince1970 * 1000))
                self.decodeCurrentTime = now//重置时间，作为下一个code的识别开始时间
            }
            DispatchQueue.main.async {
                //输出扫描结果
                let scanResult = ScanningResult(barcode: firstResult.barcodeText ?? "", type: firstResult.barcodeFormatString ?? "Unknown code",scanTime: scanTime,imageData: resultImageData,confidence: Int32(firstResult.localizationResult?.confidence ?? 0))
                self.scanResultClosure?(scanResult)
            }
        }else{
            return
        }
    }
    //MARK: - 清空手动上次识别的内容
    func clearPreResultForManually(){
        //三方不用清空
    }
    //MARK: - 打印当下的扫描配置
    private func printScannerSetting(){
        if APPConfig.isTestFlag{
//            if let settingsName = try? barcodeReader.outputSettingsToString("currentRuntimeSettings"){
//                let json = JSON(parseJSON: settingsName)
//                print(json)//json结构
//            }
        }
    }
    
    //MARK: - 在barcode上划表示线
    private func drawLineOnImage(fromImage: UIImage? = nil,corners: [CGPoint]) -> UIImage? {
        if fromImage == nil {
            return nil
        }
        //转换为只是有用的点，第一个点是leftTop，第二个点是rightTop,第三个点是rightBottom, 第四个点是leftBottom
        let converResult = self.pointsFromResult(corners)
        
        let screemSize = UIScreen.main.bounds.size
        //第一步：划线
        //将原始图片上下左右的位置转换为划线时图片大小的位置
        let format = UIGraphicsImageRendererFormat()
        format.opaque = false
        format.scale = UIScreen.main.scale
        let renderer = UIGraphicsImageRenderer(size: screemSize,format: format)
        let newImage = renderer.image{ context in
            fromImage!.draw(in: CGRect(x: 0, y: 0, width: screemSize.width, height: screemSize.height))
            //create path
            let linePath = UIBezierPath()
            //
            //pointOne,pointTwo,pointThree,pointFour是扫条形码四个角的坐标,pointOne和pointFour条形码是窄边，pointTwo和pointThree是条形码的长边
            var pointOne = converResult[0]
            let pointTwo = converResult[1]
            var pointThree = converResult[2]
            let pointFour = converResult[3]
            //条形码是正常横着放的
    //        if fabs(pointThree.x - pointOne.x) > fabs(pointThree.y - pointOne.y) {
                pointOne.y = (pointOne.y + pointFour.y) / 2
                pointOne.x = (pointOne.x + pointFour.x) / 2
                pointThree.y = (pointTwo.y + pointThree.y) / 2
                pointThree.x = (pointTwo.x + pointThree.x) / 2
    //        }else{//条形码是正常横着放的
    //            pointOne.y = (pointOne.y + pointTwo.y) / 2
    //            pointOne.x = (pointOne.x + pointTwo.x) / 2
    //            pointThree.y = (pointFour.y + pointThree.y) / 2
    //            pointThree.x = (pointFour.x + pointThree.x) / 2
    //        }
            //start point
            linePath.move(to: pointOne)
            //添加其他点
    //        linePath.addLine(to: converResult[1])
            linePath.addLine(to: pointThree)
    //        linePath.addLine(to: converResult[3])
    //        //闭合路径
    //        linePath.close()
            self.strokeColor.setStroke()
            

            linePath.lineWidth = 5
            linePath.stroke()
        }

        //第二步：剪切图片，注意：cropping中的参数是像素点，所有要乘以PPI,剪切图片的Height，扩展到线框以下scanViewTopMargin
        //Perform cropping in Core Graphics
//        guard let cutImageRef: CGImage = newImage!.cgImage?.cropping(to: CGRect(x: 0, y: 0, width: APPConfig.scanViewWidth * UIScreen.main.scale, height: APPConfig.HeightForPortrait * UIScreen.main.scale))
//            else {
//                return nil
//        }
//
//        // Return image to UIImage
//        let croppedImage: UIImage = UIImage(cgImage: cutImageRef)

        return newImage

    }
    fileprivate func pointsFromResult(_ result: [Any]) -> [CGPoint] {
        let FullScreenSize: CGSize = UIScreen.main.bounds.size
        let convertProportion = UIScreen.main.bounds.size.width / SessionConfig.quality_1920x1080.w
        let previewVerOffset = UIScreen.main.bounds.size.height / SessionConfig.quality_1920x1080.h
        
        let p0 = result[0] as! CGPoint
        let p1 = result[1] as! CGPoint
        let p2 = result[2] as! CGPoint
        let p3 = result[3] as! CGPoint
        let point0 = CGPoint(x: FullScreenSize.width - p0.y * convertProportion, y: p0.x * previewVerOffset)
        let point1 = CGPoint(x: FullScreenSize.width - p1.y * convertProportion, y: p1.x * previewVerOffset)
        let point2 = CGPoint(x: FullScreenSize.width - p2.y * convertProportion, y: p2.x * previewVerOffset)
        let point3 = CGPoint(x: FullScreenSize.width - p3.y * convertProportion, y: p3.x * previewVerOffset)
        //point0(letTop),point1(rightTop),point2(leftBottom),point3(rightBottom)是条形码四个角的坐标,
        return [point0, point1, point2, point3]
    }
}
extension DynamsoftScannerView: DCEPhotoListener{
    func photoOutputCallback(_ jpegBytes: Data) {
        DispatchQueue.main.async {
            self.takePhotoResultClosure?(jpegBytes)
        }
    }
}
